#!/usr/bin/env python

import xml.etree.ElementTree as ET
import sys

if len(sys.argv) != 2:
  print >>sys.stderr, "usage: %s <.pdml>" %(sys.argv[0])
  sys.exit(1)

if not sys.argv[1].endswith('.pdml'):
  print >>sys.stderr, "unknown file format %s" % (sys.argv[1])
  sys.exit(1)

class PacketSet:
  __slots__ = ('packets', 'file')

  def __init__(self, file):
    self.file = file
    self.packets = list()

    root = ET.parse(file)
    for packet in root.getiterator('packet'):
      self.packets.append(Packet(packet))

class Packet:
  __slots__ = ('timestamp', 'length', 'protocols')

  def __init__(self, node):
    self.protocols = list()
    protos = list(node)
    geninfo = protos[0]
    for genfield in geninfo:
      if get_attr(genfield, 'name') == 'caplen':
        self.length = get_attr(genfield, 'value')
      elif get_attr(genfield, 'name') == 'timestamp':
        self.timestamp = get_attr(genfield, 'value')
    assert(self.length > 0)
    assert(self.timestamp != None)
    assert(len(protos) > 2)
    for proto in protos[2:]:
      self.protocols.append(Protocol(proto))
    assert len(self.protocols) > 2

    def get_addresses(self):
      local = list()
      remote = list()
      for proto in self.protocols[1:3]:
        local.append()
        remote.append()

class Protocol:
  __slots__ = ('name', 'pos', 'size', 'fields')

  def __init__(self, node):
    self.fields = list()
    self.name = get_attr(node, 'name')
    self.pos = get_attr(node, 'pos')
    self.size = get_attr(node, 'size')
    assert(self.name != None)
    assert(self.pos != None)
    assert(self.size != None)
    for f in node:
      field = Field(f)
      self.fields.append(field)

  # extracts tiling for fields
  # deep controls how fields are walked through
  # False means a shallow walk, only top level fields
  # True means a depth first walk
  def extract_tiling(self, deep = False):
    assert not deep
    tiling = list()
    for f in self.fields:
      f_next = self.fields[self.fields.index(f) + 1]
      if not f.interleaved(f_next):
        tiling.append(f)
    return tiling

  def __str__(self):
    tmp = 'application protocol: %s\n' % (self.name)
    for field in self.fields:
      tmp += str(field)
      tmp += '\n'
    return tmp

class Field:
  __slots__ = ('name', 'value', 'description', 'pos', 'size', 'subfields')

  def __init__(self, node):
    self.subfields = list()
    self.name = get_attr(node, 'name')
    self.value = get_attr(node, 'value')
    self.description = get_attr(node, 'showname')
    self.pos = get_attr(node, 'pos')
    self.size = get_attr(node, 'size')
    assert self.name != None
#    assert self.value != None, 'field %s has no value' % (self.name)
#    assert self.description != None, 'field %s has no description' % (self.name)
#    assert self.size != None, 'field %s has no size' % (self.name)
#    assert self.pos != None, 'field %s has no pos' % (self.name)
    if self.description is None:
      self.description = 'unknown'
    for f in node:
      field = Field(f)
      self.subfields.append(field)

  # return a boolean indicating interleaved state of given field objects
  def interlapped(self, field):
    if field.size is None or field.pos is None:
      return False
    if self.size is None or self.pos is None:
      return False
    return ((self.pos < field.pos and self.pos + self.size > field.pos) # field.pos lays in self
      or (field.pos < self.pos and field.pos + field.size > self.pos)) # self.pos lays in field

  def __str__(self):
    if len(self.subfields) != 0:
      tmp = ''
      for subfield in self.subfields:
        tmp += str(subfield)
        tmp += '\n'
      return tmp
    else:
      return '%s: %s' % (self.name, self.description)

def get_attr(node, name):
  if name not in node.attrib:
    return None
  else:
    return node.attrib[name]

set = PacketSet(sys.argv[1])
for pkt in set.packets:
  print pkt.get_applicative_payload()
